interface ComputerPart {
    accept(visitor: ComputerPartVisitor): void;
}

class Keyboard implements ComputerPart {
    public accept(visitor: ComputerPartVisitor): void {
        visitor.visit(this);
    }
}

class Monitor implements ComputerPart {
    public accept(visitor: ComputerPartVisitor): void {
        visitor.visit(this);
    }
}

class Mouse implements ComputerPart {
    public accept(visitor: ComputerPartVisitor): void {
        visitor.visit(this);
    }
}

class Computer implements ComputerPart {
    parts: ComputerPart[];
    public constructor() {
        this.parts = [new Keyboard(), new Monitor(), new Mouse()];
    }
    public accept(visitor: ComputerPartVisitor): void {
        this.parts.forEach(part => part.accept(visitor));
        visitor.visit(this);
    }
}

interface ComputerPartVisitor {
    visit(part: Keyboard): void;
    visit(part: Monitor): void;
    visit(part: Mouse): void;
    visit(part: Computer): void;
}

class ComputerPartDisplayVisitor implements ComputerPartVisitor {
    public visit(part: Keyboard | Monitor | Mouse | Computer): void {
        switch (part.constructor) {
            case Keyboard:
                console.log("Displaying Keyboard");
                break;
            case Monitor:
                console.log("Displaying Monitor");
                break;
            case Mouse:
                console.log("Displaying Mouse");
                break;
            case Computer:
                console.log("Displaying Computer");
                break;
            default:
                console.log("Unknown Computer Part");
                break;
        }
    }
}

function main() {
    const computer: ComputerPart = new Computer();
    computer.accept(new ComputerPartDisplayVisitor());
}

main();
